//go:build !no_istio_check
// +build !no_istio_check

/*
Copyright 2022 The Authors of https://github.com/CDK-TEAM/CDK .

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package discovery

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"strings"

	"github.com/cdk-team/CDK/pkg/exploit/base"

	"github.com/cdk-team/CDK/pkg/plugin"
)

// plugin interface
type istioCheckS struct{ base.BaseExploit }

func (p istioCheckS) Desc() string {
	return "Check was the shell in a istio(service mesh) network, please note that this feature will request http://httpbin.org/get. Usage: cdk run istio-check."
}

type isioHeader struct {
	XAmznTraceId         string `json:"X-Amzn-Trace-Id"`
	XB3Sampled           string `json:"X-B3-Sampled"`
	XB3Spanid            string `json:"X-B3-Spanid"`
	XB3Traceid           string `json:"X-B3-Traceid"`
	XEnvoyAttemptCount   string `json:"X-Envoy-Attempt-Count"`
	XEnvoyPeerMetadata   string `json:"X-Envoy-Peer-Metadata"`
	XEnvoyPeerMetadataId string `json:"X-Envoy-Peer-Metadata-Id"`
}

type response struct {
	Header isioHeader `json:"headers"`
}

func (p istioCheckS) Run() bool {

	var result = response{}
	// idea from https://blog.neargle.com/backup/CIS2020%20-%20Attack%20in%20a%20Service%20Mesh%20-%20Public.pdf
	resp, err := http.Get("http://httpbin.org/get")
	if err != nil {
		log.Fatalf("cannot fetch http://httpbin.org/get , get err: %v", err)
	}
	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(&result)
	if err != nil {
		log.Printf("cannot decode JSON: %v", err)
		bodyBytes, _ := ioutil.ReadAll(resp.Body)
		log.Fatalf("respone error: %s", string(bodyBytes))
	}

	// check X-Envoy-Peer-Metadata-Id
	if strings.Contains(result.Header.XEnvoyPeerMetadataId, "sidecar") {
		log.Println("the shell is in a istio(service mesh) network.")
		log.Printf("X-Envoy-Peer-Metadata-Id is %s.\n", result.Header.XEnvoyPeerMetadataId)
		log.Printf("X-Envoy-Peer-Metadata is %s.\n", result.Header.XEnvoyPeerMetadata)
		return true
	} else {
		log.Fatalf("the shell is not in a istio(service mesh) network.")
	}

	return false
}

func init() {
	exploit := istioCheckS{}
	exploit.ExploitType = "discovery"
	plugin.RegisterExploit("istio-check", exploit)
}
